<!--
  功能：表格配置页面
  作者：Maoxiangdong
  邮箱：862755519@qq.com
  时间：2023年08月08日 17:42:48
-->
<template>
  <div ref="pageTable" style="background-color: #f5f5f5">
    <div class="page-tool-box" v-if="showActionBar">
      <div v-if="gridOptions.showButton">
        <a-button
          v-for="(item, index) in gridOptions.buttonConfig"
          @click="handleButtonClick(item)"
          :key="index"
          :type="item.type"
          style="margin-right: 8px"
          >{{ item.name }}</a-button
        >
        <!-- 自定义表格按钮 -->
        <slot name="tableButton"></slot>
      </div>
      <div v-if="gridOptions.showTool">
        <a-tooltip title="刷新" placement="top" transfer>
          <a-button shape="circle" @click="handleRefresh">
            <template #icon>
              <i class="iconfont shuaxin" style="font-size: 16px; color: #515a6e"></i>
            </template>
          </a-button>
        </a-tooltip>
        <a-tooltip title="导出" placement="top" transfer>
          <a-button shape="circle" style="margin-left: 8px" @click="handleExport">
            <template #icon>
              <i class="iconfont xiazai2" style="color: #515a6e"></i>
            </template>
          </a-button>
        </a-tooltip>
        <a-tooltip title="打印" placement="top" transfer>
          <a-button shape="circle" style="margin-left: 8px" @click="handlePrint">
            <template #icon>
              <i class="iconfont md-print" style="color: #515a6e"></i>
            </template>
          </a-button>
        </a-tooltip>
        <a-tooltip title="全屏" placement="top" transfer>
          <a-button shape="circle" @click="toggleClick" style="margin-left: 8px">
            <template #icon>
              <i class="iconfont quanping1" style="font-size: 14px; color: #515a6e"></i>
            </template>
          </a-button>
        </a-tooltip>
        <a-tooltip title="设置" placement="top" transfer>
          <a-button shape="circle" @click="handleSetting" style="margin-left: 8px">
            <template #icon>
              <i class="iconfont shezhi" style="color: #515a6e"></i>
            </template>
          </a-button>
        </a-tooltip>
      </div>
    </div>
    <div class="page-table-box">
      <vxe-grid
        v-bind="gridOptions"
        ref="xGrid"
        @checkbox-all="selectAllChangeEvent"
        @checkbox-change="selectChangeEvent"
      >
        <!-- 自定义表格插槽 -->
        <template v-for="(item, index) in slotNameList" :key="index" #[item]="{ row }">
          <slot :name="item" :content="row"></slot>
        </template>
        <!-- 自定义加载 -->
        <template #loading>
          <div class="load-box">
            <a-spin :indicator="indicator" size="large" />
          </div>
        </template>
        <!-- 自定义空数据 -->
        <template #empty>
          <div class="empty-box">
            <p>暂无数据</p>
          </div>
        </template>
      </vxe-grid>
    </div>
    <div class="page-sorter-box" v-if="gridOptions.showPage">
      <a-pagination
        v-model:current="gridOptions.page"
        v-model:page-size="gridOptions.pageSize"
        :pageSizeOptions="gridOptions.pageSizeOpts"
        :total="gridOptions.total"
        @change="handlePageChange"
        :show-total="(total) => `共 ${total} 条`"
      />
    </div>
    <!-- 导出 -->
    <Export
      :modalState="exportState"
      :modalData="exportParams"
      @onConfirm="exportConfirm"
      @onCancel="exportCancel"
    ></Export>
    <!-- 打印 -->
    <Print
      :modalState="printState"
      :modalData="printParams"
      @onConfirm="printConfirm"
      @onCancel="printCancel"
    ></Print>
    <!-- 设置 -->
    <Setting
      :modalState="settingState"
      :modalData="settingParams"
      @onConfirm="settingConfirm"
      @onCancel="settingCancel"
    ></Setting>
  </div>
</template>

<script setup>
import screenfull from 'screenfull'
import { message as Message, notification } from 'ant-design-vue'
import { LoadingOutlined } from '@ant-design/icons-vue'
import { ref, watch, computed, reactive, onMounted, onBeforeUnmount, h, nextTick } from 'vue'
import Export from './export.vue'
import Print from './print.vue'
import Setting from './setting.vue'
const props = defineProps({
  // 表格配置属性
  pageTableOptions: {
    type: Object,
    default: () => {}
  }
})
// 加载动画
const indicator = h(LoadingOutlined, {
  style: {
    fontSize: '30px'
  },
  spin: true
})
// 表格对象
const xGrid = ref(null)
// emit 事件
const emits = defineEmits([
  'onRefresh',
  'onAddData',
  'onEditData',
  'onDeleteData',
  'onSelectEvent',
  'onPageChange'
])
// 表格配置项,详见vxe-table v4官方文档 https://vxetable.cn/#/grid/api
const gridOptions = reactive({
  id: null, // 唯一标识（被某些特定的功能所依赖）
  filename: '', // 导出文件名
  sheetName: '', // 表名
  showTool: true, // 是否显示表格工具
  showPage: true, // 是否展示分页
  showButton: true, // 是否显示操作按钮
  loading: false,
  buttonConfig: [
    // 按钮配置信息
    {
      name: '新增', // 按钮名称
      type: 'primary', // type 为 primary、dashed、text
      sign: 'add', // 操作标识 添加（add），编辑（edit），删除（delete）不填则为普通按钮
      permission: 'add', // 按钮权限
      method: 'onAddData' // 点击回调方法
    },
    {
      name: '编辑', // 按钮名称
      type: 'default', // type 为 primary、dashed、text
      sign: 'edit', // 操作标识 添加（add），编辑（edit），删除（delete）不填则为普通按钮
      permission: null, // 按钮权限
      method: 'onEditData' // 点击回调方法
    },
    {
      name: '删除', // 按钮名称
      type: 'default', // type 为 primary、dashed、text
      sign: 'delete', // 操作标识 添加（add），编辑（edit），删除（delete）不填则为普通按钮
      permission: null, // 按钮权限
      method: 'onDeleteData' // 点击回调方法
    }
  ],
  border: 'full', // 是否带有边框 default（默认）, full（完整边框）, outer（外边框）, inner（内边框）, none（无边框）
  stripe: true, // 是否带有斑马纹（需要注意的是，在可编辑表格场景下，临时插入的数据不会有斑马纹样式）
  syncResize: false, // 自动跟随某个属性的变化去重新计算表格，和手动调用 recalculate 方法是一样的效果（对于通过某个属性来控制显示/隐藏切换时可能会用到）
  autoResize: false, // 自动监听父元素的变化去重新计算表格（对于父元素可能存在动态变化、显示隐藏的容器中、列宽异常等场景中的可能会用到）
  height: null, // 表格的高度；支持铺满父容器或者固定高度，如果设置 auto 为铺满父容器（如果设置为 auto，则必须确保存在父节点且不允许存在相邻元素）
  // minHeight: 800, // 表格最小高度
  // maxHeight: 800, // 表格最大高度
  round: true, // 是否有圆角
  size: 'small', // 表格尺寸 medium, small, mini
  align: 'left', // 所有列的对齐方式 left（左对齐）, center（居中对齐）, right（右对齐）
  headerAlign: 'left', // 所有的表头列的对齐方式
  footerAlign: 'left', // 所有的表头列的对齐方式
  showHeader: true, // 是否显示表头
  // showFooter: true, // 是否显示表尾
  columnConfig: {
    // 列配置信息
    resizable: true, // 调整列宽度
    isCurrent: true, // 高亮当前列
    isHover: true // 高亮当前头
  },
  rowConfig: {
    // 行配置信息
    isCurrent: true, // 高亮当前行
    isHover: true // 高亮当前头
  },
  columns: [
    { type: 'checkbox', width: 50, align: 'center', export: true, print: true, visible: true },
    { type: 'seq', width: 50, align: 'center', export: true, print: true, visible: true },
    { field: 'name', title: '姓名', width: 150, export: true, print: true, visible: true },
    { field: 'nickname', title: '昵称', width: 200, export: true, print: true, visible: true },
    { field: 'role', title: '角色', width: 150, export: true, print: true, visible: true },
    { field: 'sex', title: '性别', width: 150, export: true, print: true, visible: true },
    { field: 'age', title: '年龄', width: 150, export: true, print: true, visible: true },
    { field: 'address', title: '地址' }
  ], // 列配置信息
  total: 100, // 数据总数
  pageSizeOpts: ['10', '20', '50', '100'], // 每页条数切换的配置
  pageSize: 10, // 每页条数
  page: 1, // 当前页
  data: [
    {
      id: 10001,
      name: 'Test1',
      nickname: 'T1',
      role: 'Develop',
      sex: 'Man',
      age: 28,
      address: 'Shenzhen'
    },
    {
      id: 10002,
      name: 'Test2',
      nickname: 'T2',
      role: 'Test',
      sex: 'Women',
      age: 22,
      address: 'Guangzhou'
    },
    {
      id: 10003,
      name: 'Test3',
      nickname: 'T3',
      role: 'PM',
      sex: 'Man',
      age: 32,
      address: 'Shanghai'
    },
    {
      id: 10004,
      name: 'Test4',
      nickname: 'T4',
      role: 'Designer',
      sex: 'Women',
      age: 23,
      address: 'Shenzhen'
    },
    {
      id: 10005,
      name: 'Test5',
      nickname: 'T5',
      role: 'Develop',
      sex: 'Women',
      age: 30,
      address: 'Shanghai'
    },
    {
      id: 10006,
      name: 'Test6',
      nickname: 'T6',
      role: 'Designer',
      sex: 'Women',
      age: 21,
      address: 'Shenzhen'
    },
    {
      id: 10007,
      name: 'Test7',
      nickname: 'T7',
      role: 'Test',
      sex: 'Man',
      age: 29,
      address: 'Shenzhen'
    },
    {
      id: 10008,
      name: 'Test8',
      nickname: 'T8',
      role: 'Develop',
      sex: 'Man',
      age: 35,
      address: 'Shenzhen'
    }
  ] // 表格数据
})
// 是否显示操作栏
const showActionBar = computed(() => {
  return gridOptions.showTool || gridOptions.showButton
})
// 生成表格插槽列表
const slotNameList = computed(() => {
  let list = []
  if (gridOptions.columns) {
    gridOptions.columns.forEach((element) => {
      if (element.slots && element.slots.default && typeof element.slots.default === 'string') {
        list.push(element.slots.default)
      }
    })
  }
  return list
})
// 导出数据状态
const exportState = ref(false)
// 导出数据参数
const exportParams = reactive({
  filename: '', // 文件名
  sheetName: '', // 表名
  columns: [] // 指定列
})
// 导出
const handleExport = () => {
  exportState.value = true
  exportParams.filename = gridOptions.filename
  exportParams.sheetName = gridOptions.sheetName
  exportParams.columns = gridOptions.columns
}
// 取消导出
const exportCancel = () => {
  exportState.value = false
}
// 确认导出
const exportConfirm = (event) => {
  exportState.value = false
  const $table = xGrid.value
  const filteredArr = event.columns.filter((item) => item.export && item.field)
  // 导出当前页数据
  if ($table && event.mode == 'current') {
    $table.exportData({
      ...event,
      columns: filteredArr,
      message: false,
      data: gridOptions.data
    })
    notification.success({
      message: '导出数据提示',
      description: '导出当前页数据成功，请在下载完成后，在浏览器中打开下载的文件！'
    })
  }
  // 导出当前页选中数据
  if ($table && event.mode == 'selected') {
    $table.exportData({
      ...event,
      columns: filteredArr,
      message: false,
      data: $table.getCheckboxRecords()
    })
    notification.success({
      message: '导出数据提示',
      description: '导出当前页选中数据成功，请在下载完成后，在浏览器中打开下载的文件！'
    })
  }
  // 导出全部数据
  if ($table && event.mode == 'all') {
    notification.info({
      message: '导出数据提示',
      description:
        '暂无支持导出全部数据的功能，请使用导出当前页数据或者导出当前页选中数据，如需导出全部数据，请服务端自行兼容！'
    })
  }
}
// 打印数据状态
const printState = ref(false)
// 打印数据参数
const printParams = reactive({
  sheetName: '', // 表名
  columns: [] // 指定列
})
// 打印
const handlePrint = () => {
  printState.value = true
  printParams.sheetName = gridOptions.sheetName
  printParams.columns = gridOptions.columns
}
// 取消打印
const printCancel = () => {
  printState.value = false
}
// 确认打印
const printConfirm = (event) => {
  printState.value = false
  const $table = xGrid.value
  const filteredArr = event.columns.filter((item) => item.print && item.field)
  // 打印当前页数据
  if ($table && event.mode == 'current') {
    $table.print({
      ...event,
      columns: filteredArr,
      message: false,
      data: gridOptions.data
    })
  }
  // 打印当前页选中数据
  if ($table && event.mode == 'selected') {
    $table.print({
      ...event,
      columns: filteredArr,
      message: false,
      data: $table.getCheckboxRecords()
    })
  }
  // 打印全部数据
  if ($table && event.mode == 'all') {
    notification.info({
      message: '导出数据提示',
      description:
        '暂无支持导出全部数据的功能，请使用导出当前页数据或者导出当前页选中数据，如需导出全部数据，请服务端自行兼容！'
    })
  }
}
// 设置数据状态
const settingState = ref(false)
// 设置数据参数
const settingParams = reactive({
  border: 'full',
  stripe: true,
  syncResize: false,
  autoResize: false,
  height: null,
  round: true,
  size: 'small',
  align: 'left',
  headerAlign: 'left',
  footerAlign: 'left',
  showHeader: true,
  showFooter: true,
  columns: []
})
// 设置
const handleSetting = () => {
  settingState.value = true
  settingParams.border = gridOptions.border
  settingParams.stripe = gridOptions.stripe
  settingParams.height = gridOptions.height
  settingParams.round = gridOptions.round
  settingParams.size = gridOptions.size
  settingParams.align = gridOptions.align
  settingParams.headerAlign = gridOptions.headerAlign
  settingParams.footerAlign = gridOptions.footerAlign
  settingParams.showHeader = gridOptions.showHeader
  settingParams.columns = gridOptions.columns
}
// 取消设置
const settingCancel = () => {
  settingState.value = false
}
// 确认设置
const settingConfirm = (event) => {
  settingState.value = false
  gridOptions.border = event.border
  gridOptions.stripe = event.stripe
  gridOptions.height = event.height
  gridOptions.round = event.round
  gridOptions.size = event.size
  gridOptions.align = event.align
  gridOptions.headerAlign = event.headerAlign
  gridOptions.footerAlign = event.footerAlign
  gridOptions.showHeader = event.showHeader
  gridOptions.columns = event.columns
  const $table = xGrid.value
  gridOptions.columns.forEach(element => {
     if(element.visible){
      $table.showColumn(element.field)
     }else{
      $table.hideColumn(element.field)
     }
  });
  $table.refreshColumn()
}
// 刷新
const handleRefresh = () => {
  emits('onRefresh')
}
// 表格按钮
const handleButtonClick = (event) => {
  emits(event.method)
}
// 全选 取消全选
const selectAllChangeEvent = () => {
  const $table = xGrid.value
  if ($table) {
    const records = $table.getCheckboxRecords()
    emits('onSelectEvent', records)
  }
}
// 选择改变
const selectChangeEvent = () => {
  const $table = xGrid.value
  if ($table) {
    const records = $table.getCheckboxRecords()
    emits('onSelectEvent', records)
  }
}
// 分页信息改变 event1 页码 event2 每页条数
const handlePageChange = (event1, event2) => {
  emits('onPageChange', event1, event2)
}
/**
 * 局部全屏
 */
const pageTable = ref(null)
// 是否全屏
const isFullscreen = ref(false)
// 改变
const change = () => {
  isFullscreen.value = screenfull.isFullscreen
}
// 初始化
const init = () => {
  if (screenfull.isEnabled) {
    screenfull.on('change', change)
  }
}
// 切换全屏
const toggleClick = () => {
  if (!screenfull.isEnabled) {
    Message.error('你的浏览器不支持全屏')
    return false
  }
  screenfull.toggle(pageTable.value)
}
//销毁
const destroy = () => {
  if (screenfull.isEnabled) {
    screenfull.off('change', change)
  }
}
// onMounted
onMounted(() => {
  init()
})
// onBeforeUnmount
onBeforeUnmount(() => {
  destroy()
})
// 监听数据变化
watch(
  () => props.pageTableOptions,
  (val) => {
    if (val) {
      for (let key in val) {
        if (val[key] !== null && val[key] !== undefined) {
          if (key === 'columns') {
            val[key].forEach((element) => {
              if (element.export == undefined && element.export == null) {
                element.export = true
              }
              if (element.print == undefined && element.print == null) {
                element.print = true
              }
              if (element.visible == undefined && element.visible == null) {
                element.visible = true
              }
            })
            gridOptions.columns = val[key]
          } else {
            gridOptions[key] = val[key]
          }
        }
      }
    }
  },
  { deep: true, immediate: true }
)
</script>

<style scoped lang="scss">
.page-tool-box {
  display: flex;
  justify-content: space-between;
  border-radius: 4px;
  padding: 15px;
  background-color: #fff;
  border-radius: 4px;
  margin-top: 10px;
}

.page-table-box {
  border-radius: 4px;
  padding: 15px;
  background-color: #fff;
  border-radius: 4px;
  margin-top: 10px;
  position: relative;
}

.page-sorter-box {
  margin-top: 10px;
  text-align: right;
  border-radius: 4px;
  padding: 15px;
  background-color: #fff;
  border-radius: 4px;
}

.empty-box {
  color: #999999;
}

.load-box {
  padding: 40px 100px;
  display: flex;
  justify-content: center;
}
</style>
